#include"Task.hpp"
#include<string>
#include<vector>
#include<cstdlib>
#include<unistd.h>//这个不是c标准的一部分，是操作系统的一部分
#include<sys/types.h>
#include<iostream>
#include<cassert>
#include<cstdlib>//rand ,stand
#include<ctime>
#include<sys/wait.h>

const int processnum = 10;
std::vector<task_t> tasks;


class channel
{
public:
    channel(int cmdfd,int slaverid, const std::string &processname)
    :_cmdfd(cmdfd), _slaverid(slaverid),_processname(processname)
    {
    }
public:    
    int _cmdfd;  //文件描述符
    pid_t _slaverid;   //子进程pid
    std::string _processname;   //子进程的名字
    /* data */
};

//read(0)
void slaver(){
    while(true){
        int cmdcode=0;
        int n=read(0,&cmdcode,sizeof(int));
        if(n==sizeof(int)){
            std::cout<<"process_pid: "<<getpid()<<" :cmdcode: "<<cmdcode<<std::endl;
            if(0<=cmdcode&&cmdcode<tasks.size()) tasks[cmdcode]();
        }
        if(n==0){//管道文件关闭，n读取错误返回0；就执行break
            break;
        }
    }
}
//输入：const 
//输出：*
//输入输出 &
//标记区分

//1.初始化
void InitProcessPool(std::vector<channel>* channels){
    std::vector<int> oldfd;//记录父进程打开的文件描述符
    for(int i=0;i<processnum;i++){
        int pipefd[2];
        int n=pipe(pipefd);
        assert(!n);
        (void)n;

        pid_t id=fork();
        if(id==0){
            std::cout<<"child pid: "<<getpid()<<"  close: ";
            
            for(int &fd:oldfd){//子进程关闭fd
                std::cout<<fd<<" ";
                close(fd);
            }
            std::cout<<"\n";
            close(pipefd[1]);//关闭写端
            dup2(pipefd[0],0);//将子进程默认的读端从键盘改为，管道，现在也就是说右两个进程进程描述符对应一个文件，这个文件就是管道文件
            slaver();
            std::cout<<"over,precess_pid: "<<getpid()<<" quit"<<std::endl;
            exit(0);
        }
        sleep(1);

        //father
        close(pipefd[0]);//关闭读端
        std::string name="process"+ std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name));//创建5个管道，每个管道对应一个进程
        oldfd.push_back(pipefd[1]);//保存
    }
}

void debug(const std::vector<channel> channels){
    for(auto &c:channels){
        std::cout<<c._cmdfd<<" "<<c._slaverid<<" "<<c._processname<<std::endl;
    }
}

void menu(){
    std::cout<<"##################################"<<std::endl;
    std::cout<<"# 1.更新日志, 2.刷新出来的野怪######"<<std::endl;
    std::cout<<"# 3.检测软件是否更新 4.更新血量和蓝量"<<std::endl;
    std::cout<<"# 0.退出#"<<std::endl;
    std::cout<<"##################################"<<std::endl;
}

    
void ctrlslaver(std::vector<channel> &channels){//输入输出，
    int which=0;//取消2.选择进程，进行轮询
    //控制，测试下
    //int cnt=5;
    while(true){
        //1.选择任务
        int cmdcode=rand()%tasks.size();
        //2.选择进程
        //int  processpos=rand()%channels.size();
        //用户输入控制：
        int select=0;
        menu();
        std::cout<<"pleace enter@ "<<std::endl;
        std::cin>>select;
        if(select==0) break;
        cmdcode=select-1;

        //3.发送任务
        std::cout<<"father say: "<<"cmdcode: "<<cmdcode<<"already sendto "<< channels[which]._slaverid<<std::endl;
        write(channels[which]._cmdfd,&cmdcode,sizeof(cmdcode));
        which++;
        which%channels.size();
        // sleep(1);//用户输入控制不用等待
        
    }
}

void Quitprocess(const std::vector<channel> channels){
    int last = channels.size();
    for(int i=last;i>=0;i--){//从最后一个进程开始退出。在Initprocess中resolve
        close(channels[i]._cmdfd);
        waitpid(channels[i]._slaverid,nullptr,0);
    }

    // for(const auto &c:channels) close(c._cmdfd);//bug：创建进程后，每个进程会继承上父进程的文件描述符，继承的描述符中存在指向链接父进程和之前创建子进程的管道。
    // // sleep(5);
    // for(const auto &c:channels) waitpid(c._slaverid,nullptr,0);
    // // sleep(5);
    std::cout<<"main precess exit"<<std::endl;
    return;
}


int main(){
    LoadTask(&tasks);
    srand(time(nullptr)*getpid());
    std::vector<channel> channels;
    //1.初始化进程
    InitProcessPool(&channels);
    debug(channels);
    //2.控制进程
    ctrlslaver(channels);
    //3.退出进程
    Quitprocess(channels);
    return 0;
}





